#include "opencv2/opencv.hpp"
#include "slStruct.h"
#include "iostream"
#include "log.h"
#include "read.h"
#include "inputParam.h"
#include "calibrate.h"
#include "pattern.h"
#include "decode.h"
#include "api.h"
#include <string>
#include "opencv2/core/ocl.hpp"
#ifndef slLog
#define slLog Log::getInstance()
#endif

using namespace cv;
using namespace SL;
// dsklfksdjfjkldsf
void main()
{
    InputParamStruct inputParamStruct;
    inputParamStruct.b = 3.0f;

    // *****
    ComplementaryGrayWithPhaseShiftInputParam complementaryGrayWithPhaseShiftInputParam;
    complementaryGrayWithPhaseShiftInputParam.A = 130;
    complementaryGrayWithPhaseShiftInputParam.B = 90;
    complementaryGrayWithPhaseShiftInputParam.phaseShiftN = 12; // 12; 10
    complementaryGrayWithPhaseShiftInputParam.grayCodeN = 4;   // 4
    complementaryGrayWithPhaseShiftInputParam.cutoffPercentage = 0.5f;
    complementaryGrayWithPhaseShiftInputParam.phaseShiftCutoff = 15.0f;
    complementaryGrayWithPhaseShiftInputParam.minDistance = 150.0f;
    complementaryGrayWithPhaseShiftInputParam.maxDistance = 500.0f;
    complementaryGrayWithPhaseShiftInputParam.rowGap = 1;         // cpu only
    complementaryGrayWithPhaseShiftInputParam.colGap = 1;         // cpu only
    complementaryGrayWithPhaseShiftInputParam.imageWidth = 2736;  // 2736;  // 2736;  // 1280;  // 5472;
    complementaryGrayWithPhaseShiftInputParam.imageHeight = 1824; // 1824; // 1824; // 1024; // 3648;
    complementaryGrayWithPhaseShiftInputParam.imageSize = Size(complementaryGrayWithPhaseShiftInputParam.imageWidth, complementaryGrayWithPhaseShiftInputParam.imageHeight);
    complementaryGrayWithPhaseShiftInputParam.projectorWidth = 1280;
    complementaryGrayWithPhaseShiftInputParam.projectorHeight = 720;
    complementaryGrayWithPhaseShiftInputParam.projectorSize = Size(complementaryGrayWithPhaseShiftInputParam.projectorWidth, complementaryGrayWithPhaseShiftInputParam.projectorHeight);
    inputParamStruct.complementaryGrayWithPhaseShiftInputParam = complementaryGrayWithPhaseShiftInputParam;

    GrayBrownWoOffsetParam grayBrownWoOffsetParam;
    grayBrownWoOffsetParam.grayCodeN = 10;
    inputParamStruct.grayBrownWoOffsetParam = grayBrownWoOffsetParam;

    GrayBrownWoOffsetCalibrateParam grayBrownWoOffsetCalibrateParam;
    grayBrownWoOffsetCalibrateParam.grayCodeRowN = 8;
    grayBrownWoOffsetCalibrateParam.grayCodeColN = 10;
    grayBrownWoOffsetCalibrateParam.cornerCols = 10; // 11;
    grayBrownWoOffsetCalibrateParam.cornerRows = 7;  // 8;
    grayBrownWoOffsetCalibrateParam.squareHeight = 15.0f;
    grayBrownWoOffsetCalibrateParam.squareWidth = 15.0f;
    grayBrownWoOffsetCalibrateParam.imageWidth = 2736;  // 2736;  // 5472;  // 2736;
    grayBrownWoOffsetCalibrateParam.imageHeight = 1824; // 1824; // 3648; // 1824;
    grayBrownWoOffsetCalibrateParam.imageSize = Size(grayBrownWoOffsetCalibrateParam.imageWidth, grayBrownWoOffsetCalibrateParam.imageHeight);
    grayBrownWoOffsetCalibrateParam.projectorWidth = 1280;
    grayBrownWoOffsetCalibrateParam.projectorHeight = 720;
    grayBrownWoOffsetCalibrateParam.projectorSize = Size(grayBrownWoOffsetCalibrateParam.projectorWidth, grayBrownWoOffsetCalibrateParam.projectorHeight);
    grayBrownWoOffsetCalibrateParam.windowSize = 40;
    inputParamStruct.grayBrownWoOffsetCalibrateParam = grayBrownWoOffsetCalibrateParam;

    // *****
    GrayBrownWOffsetCalibrateParam grayBrownWOffsetCalibrateParam;
    grayBrownWOffsetCalibrateParam.grayCodeRowN = 10;
    grayBrownWOffsetCalibrateParam.grayCodeColN = 10;
    grayBrownWOffsetCalibrateParam.cornerCols = 11; // 11;
    grayBrownWOffsetCalibrateParam.cornerRows = 8;  // 8;
    grayBrownWOffsetCalibrateParam.squareHeight = 15.0f;
    grayBrownWOffsetCalibrateParam.squareWidth = 15.0f;
    grayBrownWOffsetCalibrateParam.imageWidth = 2736;  // 2736;  // 5472;  // 2736;
    grayBrownWOffsetCalibrateParam.imageHeight = 1824; // 1824; // 3648; // 1824;
    grayBrownWOffsetCalibrateParam.imageSize = Size(grayBrownWOffsetCalibrateParam.imageWidth, grayBrownWOffsetCalibrateParam.imageHeight);
    grayBrownWOffsetCalibrateParam.projectorWidth = 1280;
    grayBrownWOffsetCalibrateParam.projectorHeight = 720;
    grayBrownWOffsetCalibrateParam.projectorSize = Size(grayBrownWOffsetCalibrateParam.projectorWidth, grayBrownWOffsetCalibrateParam.projectorHeight);
    grayBrownWOffsetCalibrateParam.windowSize = 20;
    inputParamStruct.grayBrownWOffsetCalibrateParam = grayBrownWOffsetCalibrateParam;

    MonocularChessboardCalibrateParam monocularChessboardCalibrateParam;
    monocularChessboardCalibrateParam.imageWidth = 2736;  // 1624;
    monocularChessboardCalibrateParam.imageHeight = 1824; // 1240;
    monocularChessboardCalibrateParam.imageSize = Size(monocularChessboardCalibrateParam.imageWidth, monocularChessboardCalibrateParam.imageHeight);
    monocularChessboardCalibrateParam.cornerCols = 11;
    monocularChessboardCalibrateParam.cornerRows = 8;
    monocularChessboardCalibrateParam.squareHeight = 10.0f;
    monocularChessboardCalibrateParam.squareWidth = 10.0f;
    inputParamStruct.monocularChessboardCalibrateParam = monocularChessboardCalibrateParam;

    BiocularChessboardCalibrateParam biocularChessboardCalibrateParam;
    biocularChessboardCalibrateParam.imageWidth = 1624;
    biocularChessboardCalibrateParam.imageHeight = 1240;
    biocularChessboardCalibrateParam.imageSize = Size(biocularChessboardCalibrateParam.imageWidth, biocularChessboardCalibrateParam.imageHeight);
    biocularChessboardCalibrateParam.cornerCols = 11;
    biocularChessboardCalibrateParam.cornerRows = 8;
    biocularChessboardCalibrateParam.squareHeight = 10.0f;
    biocularChessboardCalibrateParam.squareWidth = 10.0f;
    inputParamStruct.biocularChessboardCalibrateParam = biocularChessboardCalibrateParam;

    ComplementaryGrayWithPhaseShiftBiocularInputParam complementaryGrayWithPhaseShiftBiocularInputParam;
    complementaryGrayWithPhaseShiftBiocularInputParam.A = 130;
    complementaryGrayWithPhaseShiftBiocularInputParam.B = 90;
    complementaryGrayWithPhaseShiftBiocularInputParam.phaseShiftN = 12; // 12; 10
    complementaryGrayWithPhaseShiftBiocularInputParam.grayCodeN = 4;
    complementaryGrayWithPhaseShiftBiocularInputParam.imageWidth = 1624;  // 2736;  // 2736;  // 1280;  // 5472;
    complementaryGrayWithPhaseShiftBiocularInputParam.imageHeight = 1240; // 1824; // 1824; // 1024; // 3648;
    complementaryGrayWithPhaseShiftBiocularInputParam.imageSize = Size(complementaryGrayWithPhaseShiftBiocularInputParam.imageWidth, complementaryGrayWithPhaseShiftBiocularInputParam.imageHeight);
    complementaryGrayWithPhaseShiftBiocularInputParam.complementaryGrayWithPhaseShiftInputParam = complementaryGrayWithPhaseShiftInputParam;
    inputParamStruct.complementaryGrayWithPhaseShiftBiocularInputParam = complementaryGrayWithPhaseShiftBiocularInputParam;

    InputParam::getInstance().setInputParamStruct(inputParamStruct);
    InputParamStruct &inputParam = InputParam::getInstance().getInputParamStruct();
    SlContent content = SLContent::getInstance().getContent();
    slLog.log("Paramater initiation finished!");
    slLog.log("Here we go!");

    // io::createFolder("D:\\code\\amiraSl\\test\\ply\\20231107_000014left__reconstruct");
    // Rectify
    // std::string trinsicPath = "D:\\code\\amiraSl\\test\\trinsic_biocular";
    // std::string savePath = "D:\\code\\amiraSl\\test\\rectifyTest";
    // std::string imageLPath = "D:\\code\\amiraSl\\test\\biocularImages\\left\\02.bmp";
    // std::string imageRPath = "D:\\code\\amiraSl\\test\\biocularImages\\right\\02.bmp";
    // Mat imageL, imageR;
    // imageL = imread(imageLPath);
    // imageR = imread(imageRPath);
    // testRectifyImage(imageL, imageR, trinsicPath, savePath);
    // return;

    // std::string trinsicPath = "D:\\code\\amiraSl\\test\\trinsic_20231031_biocular";
    // std::string savePath = "D:\\code\\amiraSl\\test\\rectifyTest";
    // std::string imageLPath = "D:\\code\\amiraSl\\test\\20231031\\stereo\\left\\Left_1.bmp";
    // std::string imageRPath = "D:\\code\\amiraSl\\test\\20231031\\stereo\\right\\right_1.bmp";
    // Mat imageL, imageR;
    // imageL = imread(imageLPath);
    // imageR = imread(imageRPath);
    // testRectifyImage(imageL, imageR, trinsicPath, savePath);
    // return;

    // content.worldCooridnates = calibrate::getWorldCoordinates(inputParam.cornerCols, inputParam.cornerRows, inputParam.squareWidth, inputParam.squareHeight);
    // content.cameraCornersList = calibrate::extractChessboradCorners(content.cameraImages(), inputParam.cornerCols, inputParam.cornerRows);
    // content.cameraIntrinsic = calibrate::cameraCalibrate(content.worldCooridnates, content.cameraCornersList, content.imageSize);
    // calibrate::estimateDirectLight(content.cameraImages(), content.imageSize, inputParam.b);
    // pattern::BitCodeList grayCode = pattern::generateGrayCode(3);

    // # GrayBrown without offset

    // ### Generate GrayBrown image without offset
    // std::string patternFolder = "D:\\code\\amiraSl\\test\\pattern";
    // generateGrayBrownWoOffsetPatternImages(patternFolder, inputParam);
    // return;

    // ### Calibrate with GrayBrown without offset
    // std::string calibrateFolder = "D:\\code\\amiraSl\\test\\20231031_000001_calibration";
    // std::string trinsicFolder = "D:\\code\\amiraSl\\test\\trinsic_20231031";
    // calibrateGrayBrownWoOffsetImages(calibrateFolder, inputParam, trinsicFolder);
    // return;

    // ### Reconstruct GrayBrown without offset
    // std::string trinsicPath = "D:\\code\\amiraSl\\test\\trinsic";
    // std::string savePath = "D:\\code\\amiraSl\\test\\ply";
    // std::string imagePath = "D:\\code\\amiraSl\\test\\20230821_144945_calibration\\20230821_144517_calibration";
    // reconstructeGrayBrownWoOffsetImages(imagePath, trinsicPath, savePath, inputParam);
    // return;

    // # ******GrayBrown with offset

    // ### Generate GrayBrown image with offset
    // std::string patternFolder = "D:\\code\\amiraSl\\test\\pattern\\WOffset";
    // generateGrayBrownWOffsetPatternImages(patternFolder, inputParam);
    // return;

    // ### Calibrate with GrayBrown with offset  
     std::string trinsicFolder  = "C:\\Work\\02Project\\amiraSl\\test\\20240110\\20240110";
     trinsicFolder  = "C:\\Work\\02Project\\amiraSl\\test\\20240115_B\\20240110\\calibration\\";
     trinsicFolder  = "C:\\Work\\02Project\\amiraSl\\test\\20240117_calibration\\out"; 
     trinsicFolder  = "C:\\Work\\02Project\\amiraSl\\test\\20240118_calibration\\calib_out"; 
     trinsicFolder  = "C:\\Work\\02Project\\amiraSl\\test\\20240118_calibration2\\calib_out"; 
    
     std::string calibrateFolder = "C:\\Work\\02Project\\amiraSl\\test\\20240110\\calibration";
     calibrateFolder = "C:\\Work\\02Project\\amiraSl\\test\\20240115_B\\20240110\\calib_param";
     calibrateFolder = "C:\\Work\\02Project\\amiraSl\\test\\20240117_calibration\\Capture\\";
     calibrateFolder = "C:\\Work\\02Project\\amiraSl\\test\\20240118_calibration\\capture\\";
     calibrateFolder = "C:\\Work\\02Project\\amiraSl\\test\\20240118_calibration2\\capture\\";
     calibrateGrayBrownWOffsetImages(calibrateFolder, inputParam, trinsicFolder);
     return;
     

    // ### Reconstruct GrayBrown with offset
    // std::string trinsicPath = "D:\\code\\amiraSl\\test\\trinisc\\20240110";
    // std::string savePath = "D:\\code\\amiraSl\\test\\ply\\20240110";
    // std::string imagePath = "E:\\20240110\\01";
    // reconstructeGrayBrownWOffsetImages(imagePath, trinsicPath, savePath, inputParam);
    // return;

    // ### Calibrate monocular camera
    // std::string calibrateFolder = "D:\\code\\amiraSl\\test\\20231031\\mono_right";
    // std::string trinsicFolder = "D:\\code\\amiraSl\\test\\trinsic_20231031_mono\\right";
    // std::string calibrateFolder = "D:\\code\\amiraSl\\test\\20231031\\mono_left";
    // std::string trinsicFolder = "D:\\code\\amiraSl\\test\\trinsic_20231031_mono\\left";
    // monocularCalibrateWithChessboard(calibrateFolder, inputParam, trinsicFolder);
    // return;

    // ### Calibrate biocular camera
    // std::string calibrateFolder = "D:\\code\\amiraSl\\test\\20231031\\stereo";
    // std::string intrinsicFolder = "D:\\code\\amiraSl\\test\\trinsic_20231031_mono";
    // std::string trinsicFolder = "D:\\code\\amiraSl\\test\\trinsic_20231031_biocular";
    // biocularCalibrateWithChessboard(calibrateFolder, intrinsicFolder, inputParam, trinsicFolder);

    // ### reconstruct biocular phaseshift
    // std::string imagePath = "D:\\code\\amiraSl\\test\\biocularPhaseShift\\6";
    // std::string trinsicFolder = "D:\\code\\amiraSl\\test\\trinsic_20231031_biocular";
    // std::string savePath = "D:\\code\\amiraSl\\test\\ply";
    // reconstructePhaseShiftBiocular(imagePath, trinsicFolder, savePath, inputParam);
    // return;

    // ### Generate phaseshift pattern
    // std::string patternFolder = "D:\\code\\amiraSl\\test\\pattern\\phaseShift12";
    // generatePhaseShiftPatternImages(patternFolder, inputParam);

   


    slLog.log("end!");
}